using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.IO;

using NBusiness.CodeDom;
using NBusiness.CodeDom.Compiler;
using NBusiness;
using NBusiness.ESharp;

using NBusiness.ESharp.Compiler;
using System.CodeDom.Compiler;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NBusiness.ESharp.Testing.Mocks;
using NBusiness.ESharp.Testing.Properties;
using NBusiness.CodeDom.Services;

namespace NBusiness.ESharp.Testing
{
	[TestClass]
	public class RelationshipTests
	{
		[TestMethod]
		public void TestSiblings()
        {
            ESharpProvider provider = new ESharpProvider();
            MockBuildErrorService errorService = new MockBuildErrorService();
            MockTypeFinder typeFinderService = new MockTypeFinder();
            provider.SetService(typeof(IBuildErrorService), errorService);

            EntityRoot root = provider.GetParser().ParseFiles(
                new EntityFile ("Relationship.Sibling1.es", Resources.Relationship_Sibling1 ),
                new EntityFile ("Relationship.Sibling2.es", Resources.Relationship_Sibling2 ));

            Assert.AreEqual(0, errorService.Errors.Count);

            Assert.AreEqual(1, root.Families.Count);
            Assert.AreEqual(2, root.Families["Relationships"].Entities.Count);

            Assert.AreEqual(2, root.Families["Relationships"].Entities[0].Relationships.Count);
            Assert.AreEqual(2, root.Families["Relationships"].Entities[1].Relationships.Count);

            Assert.AreSame(root.Families["Relationships"].Entities[0], root.Families["Relationships"].Entities[0].Relationships[0].From);
            Assert.AreSame(root.Families["Relationships"].Entities[1], root.Families["Relationships"].Entities[0].Relationships[1].From);
            Assert.AreSame(root.Families["Relationships"].Entities[1], root.Families["Relationships"].Entities[1].Relationships[0].From);
            Assert.AreSame(root.Families["Relationships"].Entities[0], root.Families["Relationships"].Entities[1].Relationships[1].From);

            Assert.AreEqual(EntityRelationshipType.Sibling, root.Families["Relationships"].Entities[0].Relationships[0].Type);
            Assert.AreEqual(EntityRelationshipType.Sibling, root.Families["Relationships"].Entities[1].Relationships[0].Type);

            Assert.AreEqual(0, root.Families["Relationships"].Entities[0].Relationships[0].On.Keys.Count);
            Assert.AreEqual(0, root.Families["Relationships"].Entities[1].Relationships[0].On.Keys.Count);

            Assert.AreSame(root.Families["Relationships"].Entities[1], root.Families["Relationships"].Entities[0].Relationships[0].With);
            Assert.AreSame(root.Families["Relationships"].Entities[0], root.Families["Relationships"].Entities[1].Relationships[0].With);
        }

		[TestMethod]
		public void TestInvalidSiblings1()
		{
            ESharpProvider provider = new ESharpProvider();
            MockBuildErrorService errorService = new MockBuildErrorService();
            MockTypeFinder typeFinderService = new MockTypeFinder();
            provider.SetService(typeof(IBuildErrorService), errorService);

            EntityRoot root = provider.GetParser().ParseFiles(
                new EntityFile ("Relationship.Sibling1.es", Resources.Relationship_Sibling1 ),
                new EntityFile ("Relationship.Sibling2.es", Resources.Relationship_Sibling2 ),
                new EntityFile ("Relationship.InvalidSibling1.es", Resources.Relationship_InvalidSibling1 ));

            Assert.AreEqual(1, errorService.Errors.Count);
            Assert.AreEqual(ESharpErrorCode.ES3007.ToString(), errorService.Errors[0].ErrorCode);
            Assert.AreEqual(ESharpEntityElementTypes.RelationshipDeclaration, errorService.Errors[0].Element.Type);
            Assert.AreEqual("Relationship.InvalidSibling1.es", errorService.Errors[0].Element.Path);
            Assert.AreEqual(EntityBuildErrorType.Error, errorService.Errors[0].Type);
        }

        [TestMethod]
		public void TestInvalidSiblings2()
		{
            ESharpProvider provider = new ESharpProvider();
            MockBuildErrorService errorService = new MockBuildErrorService();
            MockTypeFinder typeFinderService = new MockTypeFinder();
            provider.SetService(typeof(IBuildErrorService), errorService);

            EntityRoot root = provider.GetParser().ParseFiles(
                new EntityFile ("Relationship.InvalidSibling2.es", Resources.Relationship_InvalidSibling2 ),
                new EntityFile ("Relationship.Sibling3.es", Resources.Relationship_Sibling3 ));

            Assert.AreEqual(1, errorService.Errors.Count);
            Assert.AreEqual(ESharpErrorCode.ES3002.ToString(), errorService.Errors[0].ErrorCode);
            Assert.AreEqual(ESharpEntityElementTypes.RelationshipOn, errorService.Errors[0].Element.Type);
            Assert.AreEqual("Relationship.InvalidSibling2.es", errorService.Errors[0].Element.Path);
            Assert.AreEqual(EntityBuildErrorType.Error, errorService.Errors[0].Type);
        }

		[TestMethod]
		public void TestParentChild1()
		{
            ESharpProvider provider = new ESharpProvider();
            MockBuildErrorService errorService = new MockBuildErrorService();
            MockTypeFinder typeFinderService = new MockTypeFinder();
            provider.SetService(typeof(IBuildErrorService), errorService);

            EntityRoot root = provider.GetParser().ParseFiles(
                new EntityFile ("Relationship.Parent1.es", Resources.Relationship_Parent1 ),
                new EntityFile ("Relationship.Child1.es", Resources.Relationship_Child1 ));

            Assert.AreEqual(0, errorService.Errors.Count);

            Assert.AreEqual(2, root.Families["Relationships"].Entities.Count);

            Assert.AreEqual(2, root.Families["Relationships"].Entities[0].Relationships.Count);
            Assert.AreEqual(2, root.Families["Relationships"].Entities[1].Relationships.Count);

            Assert.AreEqual(EntityRelationshipType.Child, root.Families["Relationships"].Entities[0].Relationships[0].Type);
            Assert.AreEqual(EntityRelationshipType.Parent, root.Families["Relationships"].Entities[1].Relationships[0].Type);

            Assert.AreEqual(root.Families["Relationships"].Entities[1], root.Families["Relationships"].Entities[0].Relationships[0].With);
            Assert.AreEqual(root.Families["Relationships"].Entities[0], root.Families["Relationships"].Entities[0].Relationships[1].With);
            Assert.AreEqual(root.Families["Relationships"].Entities[0], root.Families["Relationships"].Entities[0].Relationships[0].From);
            Assert.AreEqual(root.Families["Relationships"].Entities[1], root.Families["Relationships"].Entities[0].Relationships[1].From);

            Assert.AreEqual(root.Families["Relationships"].Entities[0], root.Families["Relationships"].Entities[1].Relationships[0].With);
            Assert.AreEqual(root.Families["Relationships"].Entities[1], root.Families["Relationships"].Entities[1].Relationships[1].With);
            Assert.AreEqual(root.Families["Relationships"].Entities[1], root.Families["Relationships"].Entities[1].Relationships[0].From);
            Assert.AreEqual(root.Families["Relationships"].Entities[0], root.Families["Relationships"].Entities[1].Relationships[1].From);

            Assert.AreEqual(1, root.Families["Relationships"].Entities[0].Relationships[0].On.Count);
            Assert.AreEqual(1, root.Families["Relationships"].Entities[1].Relationships[0].On.Count);

            // Check the fields of Parent1 in the relationship

            foreach (EntityField f in root.Families["Relationships"].Entities[0].Relationships[0].On.Keys)
            {
                Assert.IsTrue(f.IsId);
                Assert.IsNotNull(root.Families["Relationships"].Entities[0].Relationships[0].On[f]);
                Assert.IsFalse(root.Families["Relationships"].Entities[0].Relationships[0].On[f].IsId);
            }

            // Check the fields of Child1 in the relationship
            foreach (EntityField f in root.Families["Relationships"].Entities[1].Relationships[0].On.Keys)
            {
                Assert.IsFalse(f.IsId);
                Assert.IsNotNull(root.Families["Relationships"].Entities[1].Relationships[0].On[f]);
                Assert.IsTrue(root.Families["Relationships"].Entities[1].Relationships[0].On[f].IsId);
            }
        }

		[TestMethod]
		public void TestInvalidParent1()
		{
            ESharpProvider provider = new ESharpProvider();
            MockBuildErrorService errorService = new MockBuildErrorService();
            MockTypeFinder typeFinderService = new MockTypeFinder();
            provider.SetService(typeof(IBuildErrorService), errorService);

            EntityRoot root = provider.GetParser().ParseFiles(
                new EntityFile ("Relationship.InvalidParent1.es", Resources.Relationship_InvalidParent1 ),
                new EntityFile ("Relationship.Parent1.es", Resources.Relationship_Parent1 ),
                new EntityFile ("Relationship.Child1.es", Resources.Relationship_Child1 ));

            Assert.AreEqual(2, errorService.Errors.Count);
            Assert.AreEqual(ESharpEntityElementTypes.RelationshipField, errorService.Errors[0].Element.Type);
            Assert.AreEqual("Relationship.InvalidParent1.es", errorService.Errors[0].Element.Path);
            Assert.AreEqual(ESharpEntityElementTypes.RelationshipDeclaration, errorService.Errors[1].Element.Type);
            Assert.AreEqual("Relationship.InvalidParent1.es", errorService.Errors[1].Element.Path);
        }

		[TestMethod]
		public void TestInvalidParent2()
		{
            ESharpProvider provider = new ESharpProvider();
            MockBuildErrorService errorService = new MockBuildErrorService();
            MockTypeFinder typeFinderService = new MockTypeFinder();
            provider.SetService(typeof(IBuildErrorService), errorService);

            EntityRoot root = provider.GetParser().ParseFiles(
                new EntityFile ("Relationship.InvalidParent2.es", Resources.Relationship_InvalidParent2 ),
                new EntityFile ("Relationship.Parent1.es", Resources.Relationship_Parent1 ),
                new EntityFile ("Relationship.Child1.es", Resources.Relationship_Child1 ));

            Assert.AreEqual(1, errorService.Errors.Count);
            Assert.AreEqual(ESharpEntityElementTypes.RelationshipDeclaration, errorService.Errors[0].Element.Type);
            Assert.AreEqual("Relationship.InvalidParent2.es", errorService.Errors[0].Element.Path);
        }

		[TestMethod]
		public void TestInvalidChild1()
		{
            ESharpProvider provider = new ESharpProvider();
            MockBuildErrorService errorService = new MockBuildErrorService();
            MockTypeFinder typeFinderService = new MockTypeFinder();
            provider.SetService(typeof(IBuildErrorService), errorService);

            EntityRoot root = provider.GetParser().ParseFiles(
                new EntityFile ("Relationship.InvalidChild1.es", Resources.Relationship_InvalidChild1 ),
                new EntityFile ("Relationship.Parent1.es", Resources.Relationship_Parent1 ),
                new EntityFile ("Relationship.Child1.es", Resources.Relationship_Child1 ));

            Assert.AreEqual(1, errorService.Errors.Count);
            Assert.AreEqual(ESharpEntityElementTypes.RelationshipDeclaration, errorService.Errors[0].Element.Type);
            Assert.AreEqual("Relationship.InvalidChild1.es", errorService.Errors[0].Element.Path);
		}

		[TestMethod]
		public void TestInvalidChild2()
		{
            ESharpProvider provider = new ESharpProvider();
            MockBuildErrorService errorService = new MockBuildErrorService();
            MockTypeFinder typeFinderService = new MockTypeFinder();
            provider.SetService(typeof(IBuildErrorService), errorService);

            EntityRoot root = provider.GetParser().ParseFiles(
                new EntityFile ("Relationship.InvalidChild2.es", Resources.Relationship_InvalidChild2 ),
                new EntityFile ("Relationship.Parent1.es", Resources.Relationship_Parent1 ),
                new EntityFile ("Relationship.Child1.es", Resources.Relationship_Child1 ));

            Assert.AreEqual(1, errorService.Errors.Count);
            Assert.AreEqual(ESharpEntityElementTypes.RelationshipDeclaration, errorService.Errors[0].Element.Type);
            Assert.AreEqual("Relationship.InvalidChild2.es", errorService.Errors[0].Element.Path);
        }

        [TestMethod]
        public void TestRelationshipValidation()
        {
            ESharpProvider provider = new ESharpProvider();
            MockBuildErrorService errorService = new MockBuildErrorService();
            MockTypeFinder typeFinderService = new MockTypeFinder();
            provider.SetService(typeof(IBuildErrorService), errorService);

            EntityRoot root = provider.GetParser().ParseFiles(
                new EntityFile ("Rules.Validation.es", Resources.Rules_Validation ));

            Assert.AreEqual(0, errorService.Errors.Count);
        }
        /// <summary>
        /// This test is was made to address a specific issue with sibling relationships with the same
        /// name on different entities causing an exception in the sqlscriptstemplate. Also sibling sprocs
        /// insert/delete/fetchall were being created with the same name for different relationships with the same
        /// name. That's hard to test though...
        /// </summary>
        [TestMethod]
        public void TestMultipleSiblings()
        {
            ESharpProvider provider = new ESharpProvider();
            MockBuildErrorService errorService = new MockBuildErrorService();
            MockTypeFinder typeFinderService = new MockTypeFinder();
            provider.SetService(typeof(IBuildErrorService), errorService);

            EntityRoot root = provider.GetParser().ParseFiles(
                new EntityFile ("Relationship.MultipleSiblings.es", Resources.Relationship_MultipleSiblings ));

            Assert.AreEqual(0, errorService.Errors.Count);
        }
	}
}
